package limit

import (
	"fmt"
	"sync"
	"sync/atomic"
	"time"
)

type SendEr interface {
	Send(s any) (any, error)
}
type ReceiverEr interface {
	Receiver(s any) (any, error)
}

var (
	ticker *time.Ticker
)

type RateLimiter struct {
	// 令牌桶容量
	capacity *int64
	// 当前令牌数量
	tokens *int64
	// 上次添加令牌的时间
	lastRefill time.Time
	//设置添加令牌检测延迟
	refillTime *int64
	// 每秒添加的令牌数
	refillRate *int64
	// 访问令牌桶的互斥锁
	mutex sync.Mutex
	// 停止定期添加令牌的通道
	stopChan chan struct{}
}

// NewRateLimiter 初始化对象
func NewRateLimiter(capacity int64, refillRate int64) *RateLimiter {
	tokens := capacity
	var refillTime int64 = 1
	rl := &RateLimiter{
		capacity:   &capacity,
		tokens:     &tokens,
		lastRefill: time.Now(),
		refillTime: &refillTime,
		refillRate: &refillRate,
		stopChan:   make(chan struct{}),
	}
	go rl.refillTokens()
	return rl
}

// refill 更新令牌数量
func (rl *RateLimiter) refill() {
	atomic.SwapInt64(rl.tokens, min(atomic.LoadInt64(rl.capacity), atomic.LoadInt64(rl.tokens)))
}

// refillTokens 定期添加令牌
func (rl *RateLimiter) refillTokens() {
	ticker = time.NewTicker(time.Duration(atomic.LoadInt64(rl.refillTime)) * time.Second)
	defer ticker.Stop()
	for {
		select {
		case <-ticker.C:
			now := time.Now()
			elapsed := now.Sub(rl.lastRefill).Milliseconds()
			tokensToAdd := *rl.refillRate * elapsed
			atomic.SwapInt64(rl.tokens, min(atomic.LoadInt64(rl.capacity), atomic.LoadInt64(rl.tokens)+tokensToAdd))
			rl.lastRefill = now
			//if newInterval := atomic.LoadInt64(rl.refillTime); newInterval != atomic.LoadInt64(rl.refillTime) {
			//	ticker.Reset(time.Duration(newInterval) * time.Millisecond)
			//}
		case <-rl.stopChan:
			fmt.Println("Stopping token refill goroutine.")
			return
		}
	}
}

// TryAcquire 尝试获取令牌
func (rl *RateLimiter) TryAcquire() bool {
	// 更新令牌数量
	//rl.refill()
	// 如果有令牌可用,则消耗一个令牌并返回true
	if atomic.LoadInt64(rl.tokens) > 0 {
		atomic.SwapInt64(rl.tokens, atomic.LoadInt64(rl.tokens)-1)
		return true
	}
	if atomic.LoadInt64(rl.tokens) < 0 {
		atomic.SwapInt64(rl.tokens, atomic.LoadInt64(rl.tokens))
		return false
	}
	// 否则返回false
	return false
}

// SetCapacity 动态调整令牌桶容量
func (rl *RateLimiter) SetCapacity(newCapacity int64) {
	atomic.SwapInt64(rl.capacity, newCapacity)
	atomic.SwapInt64(rl.tokens, min(atomic.LoadInt64(rl.tokens), atomic.LoadInt64(rl.capacity)))
}

// SetRefillRate 动态调整每秒添加的令牌数
func (rl *RateLimiter) SetRefillRate(newRefillRate int64) {
	atomic.SwapInt64(rl.refillRate, newRefillRate)
}

// SetRefillTime 动态调整多少毫秒添加令牌数
func (rl *RateLimiter) SetRefillTime(newRefillTime int64) {
	atomic.SwapInt64(rl.refillTime, newRefillTime)
	ticker.Reset(time.Duration(newRefillTime) * time.Millisecond)
}
func (rl *RateLimiter) GetRefill(s string) int64 {
	switch s {
	case "cap":
		return atomic.LoadInt64(rl.capacity)
	case "rate":
		return atomic.LoadInt64(rl.refillRate)
	case "time":
		return atomic.LoadInt64(rl.refillTime)
	case "token":
		return atomic.LoadInt64(rl.tokens)
	default:
		return atomic.LoadInt64(rl.tokens)
	}
}

// Stop 停止定期添加令牌
func (rl *RateLimiter) Stop() {
	close(rl.stopChan)
}

// min 比对令牌桶容量和数量，返回最小值
func min(a, b int64) int64 {
	if a < b {
		return a
	}
	return b
}
